--- title: "Plotting - ggplot2" --- Plotting - ggplot2

Intro

~2 Minute Setup

Create your R Notebook for today and double check that your workspace is clear from last time.

Load the important packages for today:

#' You only need to run this once
install.packages("scales")
install.packages("ggthemes")
library("ggplot2")
library("languageVariationAndChangeData")
library("tidyverse")
library("scales")
library("ggthemes")

Note You can find a reference for all the bits and pieces in ggplot2 here: http://ggplot2.tidyverse.org/reference/

Also, it’s easy to make mistakes, but don’t get too frustrated. Celebrate them! https://twitter.com/accidental__art

Why Plot

We are having a lesson on plotting in the middle of a course on R modelling because it is essential for you to plot your data before you try to model it. I would go so far as to say that if you haven’t made a lot of graphs of your data, and have only looked at averages, correlations, and linear model results, that you don’t really understand your data.

There’s a classic illustration of this called Anscombe’s quartet, which when plotted looks like three very distinctive patterns.

But if you fit linear models to them, they have nearly identical statistical properties.

fit_lm <- function(df){
  lm(y ~ x, data = df)
}
anscomb_models <- tidy_anscombe %>%
                    group_by(series)%>%
                    nest()%>%
                    mutate(model = map(data, fit_lm),
                           model_param_df = map(model, tidy),
                           model_glance = map(model, glance))
anscomb_models %>%
  unnest(model_param_df)%>%
  arrange(term)
anscomb_models %>%
  unnest(model_glance)

It has been even more humorously illustrated recently that you can produce data sets of almost any arbitrary shape that have nearly identical statistical properties.

Same Stats, Different Graphs: Generating Datasets with Varied Appearance and Identical Statistics through Simulated Annealing

Thinking about Plotting

It’s important to think of your figures as a report of your data. Try to take as much care in producing your plots as you do your writing, or reporting of your statistics. They are as important as (or for some readers, more important than) anything else in your paper.

“Accuracy”

When making a plot, you should strive for accuracy in:

  • Accurately representing the properties of numbers.
  • Accurately representing the nature of your data.

Take this very simple data set:

group value
A 2
B 5

For our purposes, these numbers have three properties.

  1. Order: 2 < 5, or A < B
  2. Magnitude: 5 = 2.5 \(\times\) 2, or B = 2.5 \(\times\) A
  3. Contextual Magnitude: If A and B are bars, and these are measure of the cost of a pint, then A must be a real dive (and a good deal), and B must be a little bit better, but still not too fancy. If A and B are people, and these are their number of legs, then A has an unsurprising number of legs and B has a surprising number of legs.

Here is an example of an inaccurate plot:

It successfully captures the order of A and B, but fails to capture the correct magnitude of the difference. The magnitude of the difference is thrown off because the y-axis doesn’t start at 0. In this plot, the B line is 7\(\times\) longer than the A line, but the actual magnitude of the difference is 2.5\(\times\). This produces a “lie factor” of \(\frac{7}{2.5} = 2.8\).

This isn’t just a hypothetical problem either. For example, British electoral mailers are notorious for the inaccurately portraying the magnitude of differences.

Both academic researchers and the producers of these political mailers may counter by saying

ggplot2 basic concepts

Layers, Aesthetics, Geometries and Statistics

The first thing we’re going to do is build up to creating this plot, which has one point for each speaker in the buckeye corpus, and plots their Monomorphemic retention rate against their past tense retention rate.

And then we’ll build this plot:

Layers

You should hopefully start looking at figures like this one like many of us look at the image below.

Those of use familiar with this kind of media know that the picture of the libarary is not what was originally capture by my phone. Rather there are multiple layers of effects, filters and text on top of the base image, which produce the final image. And in fact, some of these layers are crucially ordered. For example, the text would look different if it was added to the image first, and then the filters, instead of vice versa.

So too with the ggplot2 plot above. These plots are constructed out of layers. Every component of the graph, from the underlying data it’s plotting, to the coordinate system it’s plotted on, to the statistical summaries overlaid on top, to the axis labels, are layers in the plot. The consequence of this is that your use of ggplot2 will probably involve iterative addition of layer upon layer until you’re pleased with the results.

Aesthetics

The graphical properties which encode the data you’re presenting are the aesthetics of the plot. These include things like

  • x position
  • y position
  • size of elements
  • shape of elements
  • color of elements

Geometries

The primary visual items on the plots are called geometries and include things like

  • points
  • lines
  • line segments
  • bars
  • text

Some of these geometries have their own specific aesthetic settings. For example,

  • points
    • point shape
  • text
    • text labels
  • lines
    • line weight
    • line type

Statistics

You’ll also frequently want to plot statistics overlaid on top of, or instead of the raw data. Some of these include

  • Smoothing and regression lines
  • One and two dimensional binning
  • Mean and medians with confidence intervals.

The aesthetics, geometries and statistics constitute the most important layers of a plot, but for fine tuning a plot for publication, there are a number of other things you’ll want to adjust. The most common one of these are the scales, which encompass things like

  • A logarithmic x or y axis
  • Customized color scales
  • Customized point shapes, or linetypes

We’ll review many of these components as we build up the plot, and will circle back to more of them for greater detail.

Building the Plot

First, let’s refresh our memories of the graph we want to build.

This plot is composed of ten layers, which can be subdivided into five layer types. It’s not important for you to memorize these layer types, but it helps to structure the discussion.

The data layer

Every ggplot2 plot has a data layer, which defines the data set to plot, and the basic mappings of data to aesthetic elements. The data layer created with the functions ggplot() and aes(), and looks like this

ggplot(data, aes(...))

The first argument to ggplot() is a data frame (it must be a data frame), and its second argument is aes(). You’re never going to use aes() in any other context except for inside of other ggplot2 functions, so it might be best not to think of aes() as its own function, but rather as a special way of defining data-to-aesthetic mappings.

So, obviously, we first need to make the data frame we want to plot with, which we can do with a quick split-apply-combine, then spread:

(retention <- buckeye %>%
              group_by(Gram2, Speaker)%>%
              summarise(td = mean(td))%>%
              spread(Gram2, td))

With this data, we’re going to map the mono retention rates to the x-axis, and the past retention rates to the y axis, which we can do like so:

p <- ggplot(retention, aes(x = mono, y = past))
p

You can think of this plot as the base image, before we’ve added any extra layers, text or instagram filters to it. An important conceptual issue is that you are able to assign plots to variables (in this case, p). When you do this assignment, nothing special happens. But if you print out p, R will generate the plot.

The geometries layer

The next step, after defining the basic data-to-aesthetic mappings, is to add geometries to the data. We’ll discuss geometries in more detail below, but for now, we’ll add one of the simplest: points.

  p <- p + geom_point()
  p

There are a few things to take away from this step. First and foremost, the way you add new layers, of any kind, to a plot is with the + operator. And, as we’ll see in a moment, there’s no need to only add them one at a time. You can string together any number of layers to add to a plot, separated by +.

The next thing to notice is that all layers you add to a plot are, technically, functions. We didn’t pass any arguments to geom_point(), so the resulting plot represents the default behavior: solid black circular points.

If for no good reason at all we wanted to use a different point shape in the plot, we could specify it inside of geom_point().

ggplot(retention, aes(x = mono, y = past)) +
  geom_point(shape = 3)

Or, if we wanted to use larger, red points, we could specify that in geom_point() as well.

ggplot(retention, aes(x = mono, y = past))+
  geom_point(color = "red", size = 3)

Speaking of defaults, we can see a few of the default setting of ggplot2 on display here. Most striking is the light grey background, with white grid lines. Opinion varies on whether or not this is aesthetically or technically pleasing, but don’t worry, it’s adjustable.

Another default is to label the x and y axes with the column names from the data frame. I’ll inject a bit of best practice advice here, and tell you to always change the axis names. It’s nearly guaranteed that your data frame column names will make for very poor axis labels. We’ll cover how to do that shortly.

Finally, note that we didn’t need to tell geom_point() about the x and y axes. This may seem trivial, but it’s a really important, and powerful aspect of ggplot2. When you add any layer at all to a plot, it will inherit the data-to-aesthetic mappings which were defined in the data layer. We’ll discuss inheritance, and how to override, or define new data-to-aesthetic mappings within any geom.


Let’s come back to our current plot:

p

I want to add an additional geom that is just a diagonal line with an intercept of 0 and a slope of 1. That is, a line that indicates where mono == past

p <- p + geom_abline(intercept = 0, slope = 1)
p

The Statistics Layer

The final figure also includes a smoothing line, which is one of many possible statistical layers we can add to a plot.

  p <- p + stat_smooth()
  p

Cosmetic alterations

Finally, I wanted to make some cosmetic adjustments to the plot. For example, the x-axis label “mono” is not quite as useful as “Monomorphemes” would be. I also adjusted the y and x limits, added a title, changed the default “theme” from the grey background, and made it so that the plot has a square aspect ratio.

p <- p + 
    ylim(0,1)+
    xlim(0,1)+
    xlab("Monomorphemes")+
    ylab("Past Tense")+
    ggtitle("TD Retention Rates")+
    theme_minimal()+
    coord_fixed()
p

And that’s basically the whole show, except I changed the color of the points and lines to some that I like. Here’s the full code to make that whole plot:

buckeye %>%
  group_by(Speaker, Gram2) %>%
  summarise(td = mean(td))%>%
  spread(Gram2, td)%>%
  ggplot(aes(mono, past))+
    geom_point(color = "#41817F",
               alpha = 0.8)+
    geom_abline(color = "#0D4D4B",
                linetype = 2)+
    stat_smooth(color = "#0D4D4B")+
    ylim(0,1)+
    xlim(0,1)+
    xlab("Monomorphemes")+
    ylab("Past Tense")+
    ggtitle("TD Retention Rates")+
    theme_minimal()+
    coord_fixed()

Making the bar plot.

Again, we need to start out making the data set we want to work with:

buckeye %>%
  group_by(Gram2) %>%
  summarise(td = mean(td))

Then, we can start adding it to a plot. First, just the data layer.

Then, we can add geom_col() (“col” for “column”) to the graph.

buckeye %>%
  group_by(Gram2) %>%
  summarise(td = mean(td)) %>%
  filter(Gram2 %in% c("past", "semiweak", "mono"))%>%
  ggplot(aes(Gram2, td))+
    geom_col()

Things aren’t quite in the order we want them, and we can fix that with xlim().

buckeye %>%
  group_by(Gram2) %>%
  summarise(td = mean(td)) %>%
  filter(Gram2 %in% c("past", "semiweak", "mono"))%>%
  ggplot(aes(Gram2, td))+
    geom_col()+
    xlim("past", "semiweak", "mono")

Now, we can add some colors to the columns:

buckeye %>%
  group_by(Gram2) %>%
  summarise(td = mean(td)) %>%
  filter(Gram2 %in% c("past", "semiweak", "mono"))%>%
  ggplot(aes(Gram2, td))+
    geom_col(aes(fill=Gram2), color = "black")+
    xlim("past", "semiweak", "mono")

These default colors aren’t great. So I’ll use a different color palette from the ggthemes package (more info)for now:

buckeye %>%
  group_by(Gram2) %>%
  summarise(td = mean(td)) %>%
  filter(Gram2 %in% c("past", "semiweak", "mono"))%>%
  ggplot(aes(Gram2, td))+
    geom_col(aes(fill=Gram2), color = "black")+
    xlim("past", "semiweak", "mono")+
    scale_fill_few()+
    theme_minimal()

The automatically created legend needs some work though:

We should also adjust the y-axis to run up to 1, and add horizontal line to emphasize the bottom of the graph:

buckeye %>%
  group_by(Gram2) %>%
  summarise(td = mean(td)) %>%
  filter(Gram2 %in% c("past", "semiweak", "mono"))%>%
  ggplot(aes(Gram2, td))+
    geom_col(aes(fill=Gram2), color = "black")+
    xlim("past", "semiweak", "mono")+
    scale_fill_few(name = "Grammatical Class",
                   limit = c("past", "semiweak", "mono"))+
    theme_minimal()+
    ylim(0,1)+
    geom_hline(yintercept = 0)

LS0tCnRpdGxlOiAiUGxvdHRpbmcgLSBnZ3Bsb3QyIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgY29kZV9mb2xkaW5nOiBub25lCiAgICBjc3M6IGN1c3RvbS5jc3MKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgdG9jX2RlcHRoOiAzCi0tLQoKCiMgSW50cm8KCgo8ZGl2IGNsYXNzID0gImJveCBicmVhayI+CjxzcGFuIGNsYXNzID0gJ2JpZy1sYWJlbCc+fjIgTWludXRlIFNldHVwPC9zcGFuPgoKQ3JlYXRlIHlvdXIgUiBOb3RlYm9vayBmb3IgdG9kYXkgYW5kIGRvdWJsZSBjaGVjayB0aGF0IHlvdXIgd29ya3NwYWNlIGlzIGNsZWFyIGZyb20gbGFzdCB0aW1lLgoKTG9hZCB0aGUgaW1wb3J0YW50IHBhY2thZ2VzIGZvciB0b2RheToKCmBgYHtyIGV2YWwgPSBGfQojJyBZb3Ugb25seSBuZWVkIHRvIHJ1biB0aGlzIG9uY2UKaW5zdGFsbC5wYWNrYWdlcygic2NhbGVzIikKaW5zdGFsbC5wYWNrYWdlcygiZ2d0aGVtZXMiKQpgYGAKCgoKYGBge3J9CmxpYnJhcnkoImdncGxvdDIiKQpsaWJyYXJ5KCJsYW5ndWFnZVZhcmlhdGlvbkFuZENoYW5nZURhdGEiKQpsaWJyYXJ5KCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KCJzY2FsZXMiKQpsaWJyYXJ5KCJnZ3RoZW1lcyIpCmBgYAoKPC9kaXY+CgoqKk5vdGUqKiBZb3UgY2FuIGZpbmQgYSByZWZlcmVuY2UgZm9yIGFsbCB0aGUgYml0cyBhbmQgcGllY2VzIGluIGdncGxvdDIgaGVyZTogW2h0dHA6Ly9nZ3Bsb3QyLnRpZHl2ZXJzZS5vcmcvcmVmZXJlbmNlL10oaHR0cDovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvKQoKQWxzbywgaXQncyBlYXN5IHRvIG1ha2UgbWlzdGFrZXMsIGJ1dCBkb24ndCBnZXQgdG9vIGZydXN0cmF0ZWQuIENlbGVicmF0ZSB0aGVtISBbaHR0cHM6Ly90d2l0dGVyLmNvbS9hY2NpZGVudGFsX19hcnRdKGh0dHBzOi8vdHdpdHRlci5jb20vYWNjaWRlbnRhbF9fYXJ0KQoKCgojIyBXaHkgUGxvdAoKV2UgYXJlIGhhdmluZyBhIGxlc3NvbiBvbiBwbG90dGluZyBpbiB0aGUgbWlkZGxlIG9mIGEgY291cnNlIG9uIFIgbW9kZWxsaW5nIGJlY2F1c2UgaXQgaXMgKmVzc2VudGlhbCogZm9yIHlvdSB0byBwbG90IHlvdXIgZGF0YSBiZWZvcmUgeW91IHRyeSB0byBtb2RlbCBpdC4gSSB3b3VsZCBnbyBzbyBmYXIgYXMgdG8gc2F5IHRoYXQgaWYgeW91IGhhdmVuJ3QgbWFkZSBhICpsb3QqIG9mIGdyYXBocyBvZiB5b3VyIGRhdGEsIGFuZCBoYXZlIG9ubHkgbG9va2VkIGF0IGF2ZXJhZ2VzLCBjb3JyZWxhdGlvbnMsIGFuZCBsaW5lYXIgbW9kZWwgcmVzdWx0cywgdGhhdCB5b3UgZG9uJ3QgcmVhbGx5IHVuZGVyc3RhbmQgeW91ciBkYXRhLiAKClRoZXJlJ3MgYSBjbGFzc2ljIGlsbHVzdHJhdGlvbiBvZiB0aGlzIGNhbGxlZCBBbnNjb21iZSdzIHF1YXJ0ZXQsIHdoaWNoIHdoZW4gcGxvdHRlZCBsb29rcyBsaWtlIHRocmVlIHZlcnkgZGlzdGluY3RpdmUgcGF0dGVybnMuCgpgYGB7ciBlY2hvID0gRiwgZGV2ID0gJ3N2Zyd9CnRpZHlfYW5zY29tYmUgPC0gYW5zY29tYmUgJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGlkeCA9IDE6bigpKSAlPiUKICAgICAgICAgICAgICAgICAgICBnYXRoZXIoa2V5LCB2YWx1ZSwgeDE6eTQpJT4lCiAgICAgICAgICAgICAgICAgICAgc2VwYXJhdGUoa2V5LCBpbnRvID0gYygidmFyaWFibGUiLCAic2VyaWVzIiksIHNlcCA9IDEpJT4lCiAgICAgICAgICAgICAgICAgICAgc3ByZWFkKHZhcmlhYmxlLCB2YWx1ZSkKCnRpZHlfYW5zY29tYmUgJT4lCiAgZ2dwbG90KGFlcyh4LCB5KSkgKyAKICAgIGdlb21fcG9pbnQoKSArIAogICAgZmFjZXRfd3JhcCh+c2VyaWVzKQpgYGAKCkJ1dCBpZiB5b3UgZml0IGxpbmVhciBtb2RlbHMgdG8gdGhlbSwgdGhleSBoYXZlIG5lYXJseSBpZGVudGljYWwgc3RhdGlzdGljYWwgcHJvcGVydGllcy4KCmBgYHtyfQpmaXRfbG0gPC0gZnVuY3Rpb24oZGYpewogIGxtKHkgfiB4LCBkYXRhID0gZGYpCn0KYW5zY29tYl9tb2RlbHMgPC0gdGlkeV9hbnNjb21iZSAlPiUKICAgICAgICAgICAgICAgICAgICBncm91cF9ieShzZXJpZXMpJT4lCiAgICAgICAgICAgICAgICAgICAgbmVzdCgpJT4lCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKG1vZGVsID0gbWFwKGRhdGEsIGZpdF9sbSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGVsX3BhcmFtX2RmID0gbWFwKG1vZGVsLCB0aWR5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgbW9kZWxfZ2xhbmNlID0gbWFwKG1vZGVsLCBnbGFuY2UpKQoKYW5zY29tYl9tb2RlbHMgJT4lCiAgdW5uZXN0KG1vZGVsX3BhcmFtX2RmKSU+JQogIGFycmFuZ2UodGVybSkKYGBgCmBgYHtyfQphbnNjb21iX21vZGVscyAlPiUKICB1bm5lc3QobW9kZWxfZ2xhbmNlKQpgYGAKCkl0IGhhcyBiZWVuIGV2ZW4gbW9yZSBodW1vcm91c2x5IGlsbHVzdHJhdGVkIHJlY2VudGx5IHRoYXQgeW91IGNhbiBwcm9kdWNlIGRhdGEgc2V0cyBvZiBhbG1vc3QgYW55IGFyYml0cmFyeSBzaGFwZSB0aGF0IGhhdmUgbmVhcmx5IGlkZW50aWNhbCBzdGF0aXN0aWNhbCBwcm9wZXJ0aWVzLgoKIVtdKGZpZ3VyZXMvRGlub1NlcXVlbnRpYWxTbWFsbGVyLmdpZikKW1NhbWUgU3RhdHMsIERpZmZlcmVudCBHcmFwaHM6IEdlbmVyYXRpbmcgRGF0YXNldHMgd2l0aCBWYXJpZWQgQXBwZWFyYW5jZSBhbmQgSWRlbnRpY2FsIFN0YXRpc3RpY3MgdGhyb3VnaCBTaW11bGF0ZWQgQW5uZWFsaW5nXShodHRwczovL3d3dy5hdXRvZGVza3Jlc2VhcmNoLmNvbS9wdWJsaWNhdGlvbnMvc2FtZXN0YXRzKQoKIyMgVGhpbmtpbmcgYWJvdXQgUGxvdHRpbmcKCkl0J3MgaW1wb3J0YW50IHRvIHRoaW5rIG9mIHlvdXIgZmlndXJlcyBhcyBhICpyZXBvcnQqIG9mIHlvdXIgZGF0YS4gVHJ5IHRvIHRha2UgYXMgbXVjaCBjYXJlIGluIHByb2R1Y2luZyB5b3VyIHBsb3RzIGFzIHlvdSBkbyB5b3VyIHdyaXRpbmcsIG9yIHJlcG9ydGluZyBvZiB5b3VyIHN0YXRpc3RpY3MuIFRoZXkgYXJlIGFzIGltcG9ydGFudCBhcyAob3IgZm9yIHNvbWUgcmVhZGVycywgbW9yZSBpbXBvcnRhbnQgdGhhbikgYW55dGhpbmcgZWxzZSBpbiB5b3VyIHBhcGVyLgoKCiMjICJBY2N1cmFjeSIKCldoZW4gbWFraW5nIGEgcGxvdCwgeW91IHNob3VsZCBzdHJpdmUgZm9yIGFjY3VyYWN5IGluOgoKLSBBY2N1cmF0ZWx5IHJlcHJlc2VudGluZyB0aGUgcHJvcGVydGllcyBvZiBudW1iZXJzLgotIEFjY3VyYXRlbHkgcmVwcmVzZW50aW5nIHRoZSBuYXR1cmUgb2YgeW91ciBkYXRhLgoKVGFrZSB0aGlzIHZlcnkgc2ltcGxlIGRhdGEgc2V0OgoKPGRpdiBzdHlsZSA9ICJ3aWR0aDo1MCUiPgoKfCBncm91cCB8IHZhbHVlIHwKfCAtLS0tOiB8IC0tLS06IHwKfCBBIHwgMiB8CnwgQiB8IDUgfAoKPC9kaXY+CgpGb3Igb3VyIHB1cnBvc2VzLCB0aGVzZSBudW1iZXJzIGhhdmUgdGhyZWUgcHJvcGVydGllcy4KCjEuICoqT3JkZXIqKjogMiA8IDUsIG9yIEEgPCBCCjIuICoqTWFnbml0dWRlKio6IDUgPSAyLjUgJFx0aW1lcyQgMiwgb3IgQiA9IDIuNSAkXHRpbWVzJCBBCjMuICoqQ29udGV4dHVhbCBNYWduaXR1ZGUqKjogSWYgQSBhbmQgQiBhcmUgYmFycywgYW5kIHRoZXNlIGFyZSBtZWFzdXJlIG9mIHRoZSBjb3N0IG9mIGEgcGludCwgdGhlbiBBIG11c3QgYmUgYSByZWFsIGRpdmUgKGFuZCBhIGdvb2QgZGVhbCksIGFuZCBCIG11c3QgYmUgYSBsaXR0bGUgYml0IGJldHRlciwgYnV0IHN0aWxsIG5vdCB0b28gZmFuY3kuIElmIEEgYW5kIEIgYXJlIHBlb3BsZSwgYW5kIHRoZXNlIGFyZSB0aGVpciBudW1iZXIgb2YgbGVncywgdGhlbiBBIGhhcyBhbiB1bnN1cnByaXNpbmcgbnVtYmVyIG9mIGxlZ3MgYW5kIEIgaGFzIGEgc3VycHJpc2luZyBudW1iZXIgb2YgbGVncy4KCkhlcmUgaXMgYW4gZXhhbXBsZSBvZiBhbiBpbmFjY3VyYXRlIHBsb3Q6CgpgYGB7ciBmaWcud2lkdGggPSA1LzIsIGZpZy5oZWlnaHQgPSA1LzIsIGVjaG8gPSBGfQpudW0gPC0gZGF0YS5mcmFtZShncm91cCA9IGMoIkEiLCAiQiIpLAogICAgICAgICAgICAgICAgICB2YWx1ZSA9IGMoMiwgNSkpCgpnZ3Bsb3QobnVtLCBhZXMoZ3JvdXAsIHZhbHVlKSkrCiAgICBnZW9tX3NlZ21lbnQoYWVzKHhlbmQgPSBncm91cCwgeT0xLjUsIHllbmQ9dmFsdWUpLCBzaXplPTEwKSsKICAgIHRoZW1lX21pbmltYWwoKQpgYGAKCkl0IHN1Y2Nlc3NmdWxseSBjYXB0dXJlcyB0aGUgKm9yZGVyKiBvZiBBIGFuZCBCLCBidXQgZmFpbHMgdG8gY2FwdHVyZSB0aGUgY29ycmVjdCAqbWFnbml0dWRlKiBvZiB0aGUgZGlmZmVyZW5jZS4gVGhlIG1hZ25pdHVkZSBvZiB0aGUgZGlmZmVyZW5jZSBpcyB0aHJvd24gb2ZmIGJlY2F1c2UgdGhlIHktYXhpcyBkb2Vzbid0IHN0YXJ0IGF0IDAuIEluIHRoaXMgcGxvdCwgdGhlIEIgbGluZSBpcyBgciAoNS0xLjUpLygyLTEuNSlgJFx0aW1lcyQgbG9uZ2VyIHRoYW4gdGhlIEEgbGluZSwgYnV0IHRoZSBhY3R1YWwgbWFnbml0dWRlIG9mIHRoZSBkaWZmZXJlbmNlIGlzIDIuNSRcdGltZXMkLiBUaGlzIHByb2R1Y2VzIGEgImxpZSBmYWN0b3IiIG9mICRcZnJhY3s3fXsyLjV9ID0gYHIgNy8yLjVgJC4KClRoaXMgaXNuJ3QganVzdCBhIGh5cG90aGV0aWNhbCBwcm9ibGVtIGVpdGhlci4gRm9yIGV4YW1wbGUsIEJyaXRpc2ggZWxlY3RvcmFsIG1haWxlcnMgYXJlIG5vdG9yaW91cyBmb3IgdGhlIGluYWNjdXJhdGVseSBwb3J0cmF5aW5nIHRoZSBtYWduaXR1ZGUgb2YgZGlmZmVyZW5jZXMuCgohW10oZmlndXJlcy9pbmFjY3VyYXRlLnBuZykKCgpgYGB7ciBlY2hvID0gRn0Kc2NvdCA8LSBkYXRhX2ZyYW1lKHBhcnR5ID0gYygiQ29uc2VydmF0aXZlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiU05QIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGliIERlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxhYm91ciIpLAogICAgICAgICAgICAgICAgICAgbXBzID0gYygxLCA3LCAxMiwgMzkpKQpnZ3Bsb3Qoc2NvdCwgYWVzKHBhcnR5LCBtcHMsIGZpbGwgPSBwYXJ0eSkpKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBjb2xvciA9ICJibGFjayIpKwogIHhsaW0oYygiQ29uc2VydmF0aXZlIiwKICAgICAgICAgIlNOUCIsCiAgICAgICAgICJMaWIgRGVtIiwKICAgICAgICAgIkxhYm91ciIpKSsKICBzY2FsZV9maWxsX21hbnVhbChsaW1pdHM9IGMoIkNvbnNlcnZhdGl2ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTTlAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTGliIERlbSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMYWJvdXIiKSwKICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBjKCIjMDA4N2RjIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRkZGOTVEIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRkRCQjMwIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjZDUwMDAwIikpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKQm90aCBhY2FkZW1pYyByZXNlYXJjaGVycyBhbmQgdGhlIHByb2R1Y2VycyBvZiB0aGVzZSBwb2xpdGljYWwgbWFpbGVycyBtYXkgY291bnRlciBieSBzYXlpbmcKCgoKCgojIGBnZ3Bsb3QyYCBiYXNpYyBjb25jZXB0cwoKIyMgTGF5ZXJzLCBBZXN0aGV0aWNzLCBHZW9tZXRyaWVzIGFuZCBTdGF0aXN0aWNzClRoZSBmaXJzdCB0aGluZyB3ZSdyZSBnb2luZyB0byBkbyBpcyBidWlsZCB1cCB0byBjcmVhdGluZyB0aGlzIHBsb3QsIHdoaWNoIGhhcyBvbmUgcG9pbnQgZm9yIGVhY2ggc3BlYWtlciBpbiB0aGUgYGJ1Y2tleWVgIGNvcnB1cywgYW5kIHBsb3RzIHRoZWlyIE1vbm9tb3JwaGVtaWMgcmV0ZW50aW9uIHJhdGUgYWdhaW5zdCB0aGVpciBwYXN0IHRlbnNlIHJldGVudGlvbiByYXRlLgoKCgoKYGBge3IgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQpidWNrZXllICU+JQogIGdyb3VwX2J5KFNwZWFrZXIsIEdyYW0yKSAlPiUKICBzdW1tYXJpc2UodGQgPSBtZWFuKHRkKSklPiUKICBzcHJlYWQoR3JhbTIsIHRkKSU+JQogIGdncGxvdChhZXMobW9ubywgcGFzdCkpKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICIjNDE4MTdGIiwKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjgpKwogICAgZ2VvbV9hYmxpbmUoY29sb3IgPSAiIzBENEQ0QiIsCiAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IDIpKwogICAgc3RhdF9zbW9vdGgoY29sb3IgPSAiIzBENEQ0QiIpKwogICAgeWxpbSgwLDEpKwogICAgeGxpbSgwLDEpKwogICAgeGxhYigiTW9ub21vcnBoZW1lcyIpKwogICAgeWxhYigiUGFzdCBUZW5zZSIpKwogICAgZ2d0aXRsZSgiVEQgUmV0ZW50aW9uIFJhdGVzIikrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICBjb29yZF9maXhlZCgpCmBgYAoKQW5kIHRoZW4gd2UnbGwgYnVpbGQgdGhpcyBwbG90OgoKYGBge3IgZWNobyA9IEZ9CmJ1Y2tleWUgJT4lCiAgZ3JvdXBfYnkoR3JhbTIpICU+JQogIHN1bW1hcmlzZSh0ZCA9IG1lYW4odGQpKSU+JQogIGZpbHRlcihHcmFtMiAlaW4lIGMoInBhc3QiLCAic2VtaXdlYWsiLCAibW9ubyIpKSAlPiUKICBnZ3Bsb3QoYWVzKEdyYW0yLCB0ZCwgZmlsbCA9IEdyYW0yKSkrCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgY29sb3IgPSAiYmxhY2siKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApKwogICAgeGxpbSgicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikrCiAgICB5bGltKDAsMSkrCiAgICB4bGFiKCJHcmFtbWF0aWNhbCBDbGFzcyIpKwogICAgeWxhYigiUmV0ZW50aW9uIFJhdGUiKSsKICAgIHNjYWxlX2ZpbGxfZmV3KG5hbWUgPSAiR3JhbW1hdGljYWwgQ2xhc3MiLCBsaW1pdCA9IGMoInBhc3QiLCAic2VtaXdlYWsiLCAibW9ubyIpKSsKICAgIHRoZW1lX21pbmltYWwoKSsKICAgIGdndGl0bGUoIlREIFJldGVudGlvbiBSYXRlcyIpCiAgICAgIApgYGAKCgojIyMgTGF5ZXJzCgpZb3Ugc2hvdWxkIGhvcGVmdWxseSBzdGFydCBsb29raW5nIGF0IGZpZ3VyZXMgbGlrZSB0aGlzIG9uZSBsaWtlIG1hbnkgb2YgdXMgbG9vayBhdCB0aGUgaW1hZ2UgYmVsb3cuCgo8ZGl2IGNsYXNzID0gJ2hhbGYtaW1nJz4KIVtdKGZpZ3VyZXMvRW5saWdodDkuanBnKQo8L2Rpdj4KClRob3NlIG9mIHVzZSBmYW1pbGlhciB3aXRoIHRoaXMga2luZCBvZiBtZWRpYSBrbm93IHRoYXQgdGhlIHBpY3R1cmUgb2YgdGhlIGxpYmFyYXJ5IGlzIG5vdCB3aGF0IHdhcyBvcmlnaW5hbGx5IGNhcHR1cmUgYnkgbXkgcGhvbmUuIFJhdGhlciB0aGVyZSBhcmUgbXVsdGlwbGUgbGF5ZXJzIG9mIGVmZmVjdHMsIGZpbHRlcnMgYW5kIHRleHQgb24gdG9wIG9mIHRoZSBiYXNlIGltYWdlLCB3aGljaCBwcm9kdWNlIHRoZSBmaW5hbCBpbWFnZS4gQW5kIGluIGZhY3QsIHNvbWUgb2YgdGhlc2UgbGF5ZXJzIGFyZSBjcnVjaWFsbHkgb3JkZXJlZC4gRm9yIGV4YW1wbGUsIHRoZSB0ZXh0IHdvdWxkIGxvb2sgZGlmZmVyZW50IGlmIGl0IHdhcyBhZGRlZCB0byB0aGUgaW1hZ2UgZmlyc3QsIGFuZCB0aGVuIHRoZSBmaWx0ZXJzLCBpbnN0ZWFkIG9mIHZpY2UgdmVyc2EuCgoKU28gdG9vIHdpdGggdGhlIGBnZ3Bsb3QyYCBwbG90IGFib3ZlLiBUaGVzZSBwbG90cyBhcmUgY29uc3RydWN0ZWQgb3V0IG9mIF9fbGF5ZXJzX18uIEV2ZXJ5IGNvbXBvbmVudCBvZiB0aGUgZ3JhcGgsIGZyb20gdGhlIHVuZGVybHlpbmcgZGF0YSBpdCdzIHBsb3R0aW5nLCB0byB0aGUgY29vcmRpbmF0ZSBzeXN0ZW0gaXQncyBwbG90dGVkIG9uLCB0byB0aGUgc3RhdGlzdGljYWwgc3VtbWFyaWVzIG92ZXJsYWlkIG9uIHRvcCwgdG8gdGhlIGF4aXMgbGFiZWxzLCBhcmUgbGF5ZXJzIGluIHRoZSBwbG90LiBUaGUgY29uc2VxdWVuY2Ugb2YgdGhpcyBpcyB0aGF0IHlvdXIgdXNlIG9mIGBnZ3Bsb3QyYCB3aWxsIHByb2JhYmx5IGludm9sdmUgaXRlcmF0aXZlIGFkZGl0aW9uIG9mIGxheWVyIHVwb24gbGF5ZXIgdW50aWwgeW91J3JlIHBsZWFzZWQgd2l0aCB0aGUgcmVzdWx0cy4KCgojIyMgQWVzdGhldGljcwoKVGhlIGdyYXBoaWNhbCBwcm9wZXJ0aWVzIHdoaWNoIGVuY29kZSB0aGUgZGF0YSB5b3UncmUgcHJlc2VudGluZyBhcmUgdGhlIF9fYWVzdGhldGljc19fIG9mIHRoZSBwbG90LiBUaGVzZSBpbmNsdWRlIHRoaW5ncyBsaWtlCgotIHggcG9zaXRpb24KLSB5IHBvc2l0aW9uCi0gc2l6ZSBvZiBlbGVtZW50cwotIHNoYXBlIG9mIGVsZW1lbnRzCi0gY29sb3Igb2YgZWxlbWVudHMKCgojIyMgR2VvbWV0cmllcwoKVGhlIHByaW1hcnkgdmlzdWFsIGl0ZW1zIG9uIHRoZSBwbG90cyBhcmUgY2FsbGVkIF9fZ2VvbWV0cmllc19fIGFuZCBpbmNsdWRlIHRoaW5ncyBsaWtlCgoqIHBvaW50cwoqIGxpbmVzCiogbGluZSBzZWdtZW50cwoqIGJhcnMKKiB0ZXh0CgpTb21lIG9mIHRoZXNlIGdlb21ldHJpZXMgaGF2ZSB0aGVpciBvd24gc3BlY2lmaWMgYWVzdGhldGljIHNldHRpbmdzLiBGb3IgZXhhbXBsZSwKCiogcG9pbnRzCiAgICAqIHBvaW50IHNoYXBlCiogdGV4dAogICAgKiB0ZXh0IGxhYmVscwoqIGxpbmVzCiAgICAqIGxpbmUgd2VpZ2h0CiAgICAqIGxpbmUgdHlwZQogIAojIyMgU3RhdGlzdGljcwoKWW91J2xsIGFsc28gZnJlcXVlbnRseSB3YW50IHRvIHBsb3QgX19zdGF0aXN0aWNzX18gb3ZlcmxhaWQgb24gdG9wIG9mLCBvciBpbnN0ZWFkIG9mIHRoZSByYXcgZGF0YS4gU29tZSBvZiB0aGVzZSBpbmNsdWRlCgoqIFNtb290aGluZyBhbmQgcmVncmVzc2lvbiBsaW5lcwoqIE9uZSBhbmQgdHdvIGRpbWVuc2lvbmFsIGJpbm5pbmcKKiBNZWFuIGFuZCBtZWRpYW5zIHdpdGggY29uZmlkZW5jZSBpbnRlcnZhbHMuCgoKLS0tLQoKVGhlIF9fYWVzdGhldGljc19fLCBfX2dlb21ldHJpZXNfXyBhbmQgX19zdGF0aXN0aWNzX18gY29uc3RpdHV0ZSB0aGUgbW9zdCBpbXBvcnRhbnQgX19sYXllcnNfXyBvZiBhIHBsb3QsIGJ1dCBmb3IgZmluZSB0dW5pbmcgYSBwbG90IGZvciBwdWJsaWNhdGlvbiwgdGhlcmUgYXJlIGEgbnVtYmVyIG9mIG90aGVyIHRoaW5ncyB5b3UnbGwgd2FudCB0byBhZGp1c3QuIFRoZSBtb3N0IGNvbW1vbiBvbmUgb2YgdGhlc2UgYXJlIHRoZSBfX3NjYWxlc19fLCB3aGljaCBlbmNvbXBhc3MgdGhpbmdzIGxpa2UKCiogQSBsb2dhcml0aG1pYyB4IG9yIHkgYXhpcwoqIEN1c3RvbWl6ZWQgY29sb3Igc2NhbGVzCiogQ3VzdG9taXplZCBwb2ludCBzaGFwZXMsIG9yIGxpbmV0eXBlcwoKV2UnbGwgcmV2aWV3IG1hbnkgb2YgdGhlc2UgY29tcG9uZW50cyBhcyB3ZSBidWlsZCB1cCB0aGUgcGxvdCwgYW5kIHdpbGwgY2lyY2xlIGJhY2sgdG8gbW9yZSBvZiB0aGVtIGZvciBncmVhdGVyIGRldGFpbC4KCgoKIyBCdWlsZGluZyB0aGUgUGxvdAoKRmlyc3QsIGxldCdzIHJlZnJlc2ggb3VyIG1lbW9yaWVzIG9mIHRoZSBncmFwaCB3ZSB3YW50IHRvIGJ1aWxkLgoKYGBge3IgZWNobyA9IEYsIG1lc3NhZ2UgPSBGfQpidWNrZXllICU+JQogIGdyb3VwX2J5KFNwZWFrZXIsIEdyYW0yKSAlPiUKICBzdW1tYXJpc2UodGQgPSBtZWFuKHRkKSklPiUKICBzcHJlYWQoR3JhbTIsIHRkKSU+JQogIGdncGxvdChhZXMobW9ubywgcGFzdCkpKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICIjNDE4MTdGIiwKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjgpKwogICAgZ2VvbV9hYmxpbmUoY29sb3IgPSAiIzBENEQ0QiIsCiAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IDIpKwogICAgc3RhdF9zbW9vdGgoY29sb3IgPSAiIzBENEQ0QiIpKwogICAgeWxpbSgwLDEpKwogICAgeGxpbSgwLDEpKwogICAgeGxhYigiTW9ub21vcnBoZW1lcyIpKwogICAgeWxhYigiUGFzdCBUZW5zZSIpKwogICAgZ2d0aXRsZSgiVEQgUmV0ZW50aW9uIFJhdGVzIikrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICBjb29yZF9maXhlZCgpCmBgYAoKVGhpcyBwbG90IGlzIGNvbXBvc2VkIG9mIHRlbiBsYXllcnMsIHdoaWNoIGNhbiBiZSBzdWJkaXZpZGVkIGludG8gZml2ZSBsYXllciB0eXBlcy4gSXQncyBub3QgaW1wb3J0YW50IGZvciB5b3UgdG8gbWVtb3JpemUgdGhlc2UgbGF5ZXIgdHlwZXMsIGJ1dCBpdCBoZWxwcyB0byBzdHJ1Y3R1cmUgdGhlIGRpc2N1c3Npb24uCgoKIyMgVGhlIGRhdGEgbGF5ZXIKCkV2ZXJ5IGBnZ3Bsb3QyYCBwbG90IGhhcyBhIGRhdGEgbGF5ZXIsIHdoaWNoIGRlZmluZXMgdGhlIGRhdGEgc2V0IHRvIHBsb3QsIGFuZCB0aGUgYmFzaWMgbWFwcGluZ3Mgb2YgZGF0YSB0byBhZXN0aGV0aWMgZWxlbWVudHMuIFRoZSBkYXRhIGxheWVyIGNyZWF0ZWQgd2l0aCB0aGUgZnVuY3Rpb25zIGBnZ3Bsb3QoKWAgYW5kIGBhZXMoKWAsIGFuZCBsb29rcyBsaWtlIHRoaXMKCmBgYHtyIGV2YWw9Rn0KZ2dwbG90KGRhdGEsIGFlcyguLi4pKQpgYGAKClRoZSBmaXJzdCBhcmd1bWVudCB0byBgZ2dwbG90KClgIGlzIGEgZGF0YSBmcmFtZSAoaXQgX211c3RfIGJlIGEgZGF0YSBmcmFtZSksIGFuZCBpdHMgc2Vjb25kIGFyZ3VtZW50IGlzIGBhZXMoKWAuIFlvdSdyZSBuZXZlciBnb2luZyB0byB1c2UgYGFlcygpYCBpbiBhbnkgb3RoZXIgY29udGV4dCBleGNlcHQgZm9yIGluc2lkZSBvZiBvdGhlciBgZ2dwbG90MmAgZnVuY3Rpb25zLCBzbyBpdCBtaWdodCBiZSBiZXN0IG5vdCB0byB0aGluayBvZiBgYWVzKClgIGFzIGl0cyBvd24gZnVuY3Rpb24sIGJ1dCByYXRoZXIgYXMgYSBzcGVjaWFsIHdheSBvZiBkZWZpbmluZyBkYXRhLXRvLWFlc3RoZXRpYyBtYXBwaW5ncy4KClNvLCBvYnZpb3VzbHksIHdlIGZpcnN0IG5lZWQgdG8gKm1ha2UqIHRoZSBkYXRhIGZyYW1lIHdlIHdhbnQgdG8gcGxvdCB3aXRoLCB3aGljaCB3ZSBjYW4gZG8gd2l0aCBhIHF1aWNrIHNwbGl0LWFwcGx5LWNvbWJpbmUsIHRoZW4gc3ByZWFkOgoKYGBge3J9CihyZXRlbnRpb24gPC0gYnVja2V5ZSAlPiUKICAgICAgICAgICAgICBncm91cF9ieShHcmFtMiwgU3BlYWtlciklPiUKICAgICAgICAgICAgICBzdW1tYXJpc2UodGQgPSBtZWFuKHRkKSklPiUKICAgICAgICAgICAgICBzcHJlYWQoR3JhbTIsIHRkKSkKYGBgCgoKV2l0aCB0aGlzIGRhdGEsIHdlJ3JlIGdvaW5nIHRvIG1hcCB0aGUgYG1vbm9gIHJldGVudGlvbiByYXRlcyB0byB0aGUgeC1heGlzLCBhbmQgdGhlIGBwYXN0YCByZXRlbnRpb24gcmF0ZXMgdG8gdGhlIHkgYXhpcywgd2hpY2ggd2UgY2FuIGRvIGxpa2Ugc286CgpgYGB7cn0KcCA8LSBnZ3Bsb3QocmV0ZW50aW9uLCBhZXMoeCA9IG1vbm8sIHkgPSBwYXN0KSkKcApgYGAKCgoKWW91IGNhbiB0aGluayBvZiB0aGlzIHBsb3QgYXMgdGhlIGJhc2UgaW1hZ2UsIGJlZm9yZSB3ZSd2ZSBhZGRlZCBhbnkgZXh0cmEgbGF5ZXJzLCB0ZXh0IG9yIGluc3RhZ3JhbSBmaWx0ZXJzIHRvIGl0LiBBbiBpbXBvcnRhbnQgY29uY2VwdHVhbCBpc3N1ZSBpcyB0aGF0IHlvdSBhcmUgYWJsZSB0byBhc3NpZ24gcGxvdHMgdG8gdmFyaWFibGVzIChpbiB0aGlzIGNhc2UsIGBwYCkuIFdoZW4geW91IGRvIHRoaXMgYXNzaWdubWVudCwgbm90aGluZyBzcGVjaWFsIGhhcHBlbnMuIEJ1dCBpZiB5b3UgcHJpbnQgb3V0IGBwYCwgUiB3aWxsIGdlbmVyYXRlIHRoZSBwbG90LiAKCgojIyBUaGUgZ2VvbWV0cmllcyBsYXllcgoKVGhlIG5leHQgc3RlcCwgYWZ0ZXIgZGVmaW5pbmcgdGhlIGJhc2ljIGRhdGEtdG8tYWVzdGhldGljIG1hcHBpbmdzLCBpcyB0byBhZGQgZ2VvbWV0cmllcyB0byB0aGUgZGF0YS4gV2UnbGwgZGlzY3VzcyBnZW9tZXRyaWVzIGluIG1vcmUgZGV0YWlsIGJlbG93LCBidXQgZm9yIG5vdywgd2UnbGwgYWRkIG9uZSBvZiB0aGUgc2ltcGxlc3Q6IHBvaW50cy4KCmBgYHtyIGZpZy5wb3MgPSAiY2VudGVyIixmaWcud2lkdGggPSA4LzEuNSwgZmlnLmhlaWdodD01LzEuNX0KICBwIDwtIHAgKyBnZW9tX3BvaW50KCkKICBwCmBgYAoKVGhlcmUgYXJlIGEgZmV3IHRoaW5ncyB0byB0YWtlIGF3YXkgZnJvbSB0aGlzIHN0ZXAuIEZpcnN0IGFuZCBmb3JlbW9zdCwgdGhlIHdheSB5b3UgYWRkIG5ldyBsYXllcnMsIG9mIGFueSBraW5kLCB0byBhIHBsb3QgaXMgd2l0aCB0aGUgYCtgIG9wZXJhdG9yLiBBbmQsIGFzIHdlJ2xsIHNlZSBpbiBhIG1vbWVudCwgdGhlcmUncyBubyBuZWVkIHRvIG9ubHkgYWRkIHRoZW0gb25lIGF0IGEgdGltZS4gWW91IGNhbiBzdHJpbmcgdG9nZXRoZXIgYW55IG51bWJlciBvZiBsYXllcnMgdG8gYWRkIHRvIGEgcGxvdCwgc2VwYXJhdGVkIGJ5IGArYC4KClRoZSBuZXh0IHRoaW5nIHRvIG5vdGljZSBpcyB0aGF0IGFsbCBsYXllcnMgeW91IGFkZCB0byBhIHBsb3QgYXJlLCB0ZWNobmljYWxseSwgZnVuY3Rpb25zLiBXZSBkaWRuJ3QgcGFzcyBhbnkgYXJndW1lbnRzIHRvIGBnZW9tX3BvaW50KClgLCBzbyB0aGUgcmVzdWx0aW5nIHBsb3QgcmVwcmVzZW50cyB0aGUgZGVmYXVsdCBiZWhhdmlvcjogc29saWQgYmxhY2sgY2lyY3VsYXIgcG9pbnRzLgoKSWYgZm9yIG5vIGdvb2QgcmVhc29uIGF0IGFsbCB3ZSB3YW50ZWQgdG8gdXNlIGEgZGlmZmVyZW50IHBvaW50IHNoYXBlIGluIHRoZSBwbG90LCB3ZSBjb3VsZCBzcGVjaWZ5IGl0IGluc2lkZSBvZiBgZ2VvbV9wb2ludCgpYC4KCmBgYHtyIGZpZy5wb3MgPSAiY2VudGVyIixmaWcud2lkdGggPSA4LzEuNSwgZmlnLmhlaWdodD01LzEuNSwgdGlkeSA9IEZ9CmdncGxvdChyZXRlbnRpb24sIGFlcyh4ID0gbW9ubywgeSA9IHBhc3QpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDMpCmBgYAoKT3IsIGlmIHdlIHdhbnRlZCB0byB1c2UgbGFyZ2VyLCByZWQgcG9pbnRzLCB3ZSBjb3VsZCBzcGVjaWZ5IHRoYXQgaW4gYGdlb21fcG9pbnQoKWAgYXMgd2VsbC4KYGBge3IgZmlnLnBvcyA9ICJjZW50ZXIiLGZpZy53aWR0aCA9IDgvMS41LCBmaWcuaGVpZ2h0PTUvMS41LCB0aWR5ID0gRn0KZ2dwbG90KHJldGVudGlvbiwgYWVzKHggPSBtb25vLCB5ID0gcGFzdCkpKwogIGdlb21fcG9pbnQoY29sb3IgPSAicmVkIiwgc2l6ZSA9IDMpCmBgYAoKU3BlYWtpbmcgb2YgZGVmYXVsdHMsIHdlIGNhbiBzZWUgYSBmZXcgb2YgdGhlIGRlZmF1bHQgc2V0dGluZyBvZiBgZ2dwbG90MmAgb24gZGlzcGxheSBoZXJlLiBNb3N0IHN0cmlraW5nIGlzIHRoZSBsaWdodCBncmV5IGJhY2tncm91bmQsIHdpdGggd2hpdGUgZ3JpZCBsaW5lcy4gT3BpbmlvbiB2YXJpZXMgb24gd2hldGhlciBvciBub3QgdGhpcyBpcyBhZXN0aGV0aWNhbGx5IG9yIHRlY2huaWNhbGx5IHBsZWFzaW5nLCBidXQgZG9uJ3Qgd29ycnksIGl0J3MgYWRqdXN0YWJsZS4gCgpBbm90aGVyIGRlZmF1bHQgaXMgdG8gbGFiZWwgdGhlIHggYW5kIHkgYXhlcyB3aXRoIHRoZSBjb2x1bW4gbmFtZXMgZnJvbSB0aGUgZGF0YSBmcmFtZS4gSSdsbCBpbmplY3QgYSBiaXQgb2YgYmVzdCBwcmFjdGljZSBhZHZpY2UgaGVyZSwgYW5kIHRlbGwgeW91IHRvIF9hbHdheXNfIGNoYW5nZSB0aGUgYXhpcyBuYW1lcy4gSXQncyBuZWFybHkgZ3VhcmFudGVlZCB0aGF0IHlvdXIgZGF0YSBmcmFtZSBjb2x1bW4gbmFtZXMgd2lsbCBtYWtlIGZvciB2ZXJ5IHBvb3IgYXhpcyBsYWJlbHMuIFdlJ2xsIGNvdmVyIGhvdyB0byBkbyB0aGF0IHNob3J0bHkuCgpGaW5hbGx5LCBub3RlIHRoYXQgd2UgZGlkbid0IG5lZWQgdG8gdGVsbCBgZ2VvbV9wb2ludCgpYCBhYm91dCB0aGUgeCBhbmQgeSBheGVzLiBUaGlzIG1heSBzZWVtIHRyaXZpYWwsIGJ1dCBpdCdzIGEgcmVhbGx5IGltcG9ydGFudCwgYW5kIHBvd2VyZnVsIGFzcGVjdCBvZiBgZ2dwbG90MmAuIFdoZW4geW91IGFkZCBhbnkgbGF5ZXIgYXQgYWxsIHRvIGEgcGxvdCwgaXQgd2lsbCBfX2luaGVyaXRfXyB0aGUgZGF0YS10by1hZXN0aGV0aWMgbWFwcGluZ3Mgd2hpY2ggd2VyZSBkZWZpbmVkIGluIHRoZSBkYXRhIGxheWVyLiBXZSdsbCBkaXNjdXNzIGluaGVyaXRhbmNlLCBhbmQgaG93IHRvIG92ZXJyaWRlLCBvciBkZWZpbmUgbmV3IGRhdGEtdG8tYWVzdGhldGljIG1hcHBpbmdzIHdpdGhpbiBhbnkgZ2VvbS4KCgoKLS0tCgpMZXQncyBjb21lIGJhY2sgdG8gb3VyIGN1cnJlbnQgcGxvdDoKCmBgYHtyfQpwCmBgYAoKSSB3YW50IHRvIGFkZCBhbiBhZGRpdGlvbmFsIGdlb20gdGhhdCBpcyBqdXN0IGEgZGlhZ29uYWwgbGluZSB3aXRoIGFuIGludGVyY2VwdCBvZiAwIGFuZCBhIHNsb3BlIG9mIDEuIFRoYXQgaXMsIGEgbGluZSB0aGF0IGluZGljYXRlcyB3aGVyZSBgbW9ub2AgPT0gYHBhc3RgCgpgYGB7cn0KcCA8LSBwICsgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxKQpwCmBgYAoKIyMgVGhlIFN0YXRpc3RpY3MgTGF5ZXIKClRoZSBmaW5hbCBmaWd1cmUgYWxzbyBpbmNsdWRlcyBhIHNtb290aGluZyBsaW5lLCB3aGljaCBpcyBvbmUgb2YgbWFueSBwb3NzaWJsZSBzdGF0aXN0aWNhbCBsYXllcnMgd2UgY2FuIGFkZCB0byBhIHBsb3QuCmBgYHtyIGZpZy53aWR0aCA9IDgvMS41LCBmaWcuaGVpZ2h0PTUvMS41fQogIHAgPC0gcCArIHN0YXRfc21vb3RoKCkKICBwCmBgYAoKIyMgQ29zbWV0aWMgYWx0ZXJhdGlvbnMKRmluYWxseSwgSSB3YW50ZWQgdG8gbWFrZSBzb21lIGNvc21ldGljIGFkanVzdG1lbnRzIHRvIHRoZSBwbG90LiBGb3IgZXhhbXBsZSwgdGhlIHgtYXhpcyBsYWJlbCAibW9ubyIgaXMgbm90IHF1aXRlIGFzIHVzZWZ1bCBhcyAiTW9ub21vcnBoZW1lcyIgd291bGQgYmUuIEkgYWxzbyBhZGp1c3RlZCB0aGUgeSBhbmQgeCBsaW1pdHMsIGFkZGVkIGEgdGl0bGUsIGNoYW5nZWQgdGhlIGRlZmF1bHQgInRoZW1lIiBmcm9tIHRoZSBncmV5IGJhY2tncm91bmQsIGFuZCBtYWRlIGl0IHNvIHRoYXQgdGhlIHBsb3QgaGFzIGEgc3F1YXJlIGFzcGVjdCByYXRpby4KCmBgYHtyIHRpZHkgPSBGLGZpZy53aWR0aCA9IDgvMS41LCBmaWcuaGVpZ2h0PTUvMS41LCB3YXJuaW5nID0gRiwgbWVzc2FnZSAgPUYgfQpwIDwtIHAgKyAKICAgIHlsaW0oMCwxKSsKICAgIHhsaW0oMCwxKSsKICAgIHhsYWIoIk1vbm9tb3JwaGVtZXMiKSsKICAgIHlsYWIoIlBhc3QgVGVuc2UiKSsKICAgIGdndGl0bGUoIlREIFJldGVudGlvbiBSYXRlcyIpKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgY29vcmRfZml4ZWQoKQpwCmBgYAoKCgoKQW5kIHRoYXQncyBiYXNpY2FsbHkgdGhlIHdob2xlIHNob3csIGV4Y2VwdCBJIGNoYW5nZWQgdGhlIGNvbG9yIG9mIHRoZSBwb2ludHMgYW5kIGxpbmVzIHRvIHNvbWUgdGhhdCBJIGxpa2UuIEhlcmUncyB0aGUgZnVsbCBjb2RlIHRvIG1ha2UgdGhhdCB3aG9sZSBwbG90OgoKCmBgYHtyICBtZXNzYWdlID0gRn0KYnVja2V5ZSAlPiUKICBncm91cF9ieShTcGVha2VyLCBHcmFtMikgJT4lCiAgc3VtbWFyaXNlKHRkID0gbWVhbih0ZCkpJT4lCiAgc3ByZWFkKEdyYW0yLCB0ZCklPiUKICBnZ3Bsb3QoYWVzKG1vbm8sIHBhc3QpKSsKICAgIGdlb21fcG9pbnQoY29sb3IgPSAiIzQxODE3RiIsCiAgICAgICAgICAgICAgIGFscGhhID0gMC44KSsKICAgIGdlb21fYWJsaW5lKGNvbG9yID0gIiMwRDRENEIiLAogICAgICAgICAgICAgICAgbGluZXR5cGUgPSAyKSsKICAgIHN0YXRfc21vb3RoKGNvbG9yID0gIiMwRDRENEIiKSsKICAgIHlsaW0oMCwxKSsKICAgIHhsaW0oMCwxKSsKICAgIHhsYWIoIk1vbm9tb3JwaGVtZXMiKSsKICAgIHlsYWIoIlBhc3QgVGVuc2UiKSsKICAgIGdndGl0bGUoIlREIFJldGVudGlvbiBSYXRlcyIpKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgY29vcmRfZml4ZWQoKQpgYGAKCgojIE1ha2luZyB0aGUgYmFyIHBsb3QuCgpBZ2Fpbiwgd2UgbmVlZCB0byBzdGFydCBvdXQgbWFraW5nIHRoZSBkYXRhIHNldCB3ZSB3YW50IHRvIHdvcmsgd2l0aDoKCmBgYHtyfQpidWNrZXllICU+JQogIGdyb3VwX2J5KEdyYW0yKSAlPiUKICBzdW1tYXJpc2UodGQgPSBtZWFuKHRkKSkKYGBgCgoKVGhlbiwgd2UgY2FuIHN0YXJ0IGFkZGluZyBpdCB0byBhIHBsb3QuIEZpcnN0LCBqdXN0IHRoZSBkYXRhIGxheWVyLgoKYGBge3J9CmJ1Y2tleWUgJT4lCiAgZ3JvdXBfYnkoR3JhbTIpICU+JQogIHN1bW1hcmlzZSh0ZCA9IG1lYW4odGQpKSAlPiUKICBmaWx0ZXIoR3JhbTIgJWluJSBjKCJwYXN0IiwgInNlbWl3ZWFrIiwgIm1vbm8iKSklPiUKICBnZ3Bsb3QoYWVzKEdyYW0yLCB0ZCkpCmBgYAoKClRoZW4sIHdlIGNhbiBhZGQgYGdlb21fY29sKClgICgiY29sIiBmb3IgImNvbHVtbiIpIHRvIHRoZSBncmFwaC4KCmBgYHtyfQpidWNrZXllICU+JQogIGdyb3VwX2J5KEdyYW0yKSAlPiUKICBzdW1tYXJpc2UodGQgPSBtZWFuKHRkKSkgJT4lCiAgZmlsdGVyKEdyYW0yICVpbiUgYygicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikpJT4lCiAgZ2dwbG90KGFlcyhHcmFtMiwgdGQpKSsKICAgIGdlb21fY29sKCkKYGBgCgoKVGhpbmdzIGFyZW4ndCBxdWl0ZSBpbiB0aGUgb3JkZXIgd2Ugd2FudCB0aGVtLCBhbmQgd2UgY2FuIGZpeCB0aGF0IHdpdGggYHhsaW0oKWAuCgpgYGB7cn0KYnVja2V5ZSAlPiUKICBncm91cF9ieShHcmFtMikgJT4lCiAgc3VtbWFyaXNlKHRkID0gbWVhbih0ZCkpICU+JQogIGZpbHRlcihHcmFtMiAlaW4lIGMoInBhc3QiLCAic2VtaXdlYWsiLCAibW9ubyIpKSU+JQogIGdncGxvdChhZXMoR3JhbTIsIHRkKSkrCiAgICBnZW9tX2NvbCgpKwogICAgeGxpbSgicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikKYGBgCgoKTm93LCB3ZSBjYW4gYWRkIHNvbWUgY29sb3JzIHRvIHRoZSBjb2x1bW5zOgoKYGBge3J9CmJ1Y2tleWUgJT4lCiAgZ3JvdXBfYnkoR3JhbTIpICU+JQogIHN1bW1hcmlzZSh0ZCA9IG1lYW4odGQpKSAlPiUKICBmaWx0ZXIoR3JhbTIgJWluJSBjKCJwYXN0IiwgInNlbWl3ZWFrIiwgIm1vbm8iKSklPiUKICBnZ3Bsb3QoYWVzKEdyYW0yLCB0ZCkpKwogICAgZ2VvbV9jb2woYWVzKGZpbGw9R3JhbTIpLCBjb2xvciA9ICJibGFjayIpKwogICAgeGxpbSgicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikKYGBgCgoKVGhlc2UgZGVmYXVsdCBjb2xvcnMgYXJlbid0ICpncmVhdCouIFNvIEknbGwgdXNlIGEgZGlmZmVyZW50IGNvbG9yIHBhbGV0dGUgZnJvbSB0aGUgYGdndGhlbWVzYCBwYWNrYWdlIChbbW9yZSBpbmZvXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvZ2d0aGVtZXMvdmlnbmV0dGVzL2dndGhlbWVzLmh0bWwpKWZvciBub3c6CgoKYGBge3J9CmJ1Y2tleWUgJT4lCiAgZ3JvdXBfYnkoR3JhbTIpICU+JQogIHN1bW1hcmlzZSh0ZCA9IG1lYW4odGQpKSAlPiUKICBmaWx0ZXIoR3JhbTIgJWluJSBjKCJwYXN0IiwgInNlbWl3ZWFrIiwgIm1vbm8iKSklPiUKICBnZ3Bsb3QoYWVzKEdyYW0yLCB0ZCkpKwogICAgZ2VvbV9jb2woYWVzKGZpbGw9R3JhbTIpLCBjb2xvciA9ICJibGFjayIpKwogICAgeGxpbSgicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikrCiAgICBzY2FsZV9maWxsX2ZldygpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKClRoZSBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgbGVnZW5kIG5lZWRzIHNvbWUgd29yayB0aG91Z2g6CgoKYGBge3J9CmJ1Y2tleWUgJT4lCiAgZ3JvdXBfYnkoR3JhbTIpICU+JQogIHN1bW1hcmlzZSh0ZCA9IG1lYW4odGQpKSAlPiUKICBmaWx0ZXIoR3JhbTIgJWluJSBjKCJwYXN0IiwgInNlbWl3ZWFrIiwgIm1vbm8iKSklPiUKICBnZ3Bsb3QoYWVzKEdyYW0yLCB0ZCkpKwogICAgZ2VvbV9jb2woYWVzKGZpbGw9R3JhbTIpLCBjb2xvciA9ICJibGFjayIpKwogICAgeGxpbSgicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikrCiAgICBzY2FsZV9maWxsX2ZldyhuYW1lID0gIkdyYW1tYXRpY2FsIENsYXNzIiwKICAgICAgICAgICAgICAgICAgIGxpbWl0ID0gYygicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikpKwogICAgdGhlbWVfbWluaW1hbCgpCmBgYAoKCldlIHNob3VsZCBhbHNvIGFkanVzdCB0aGUgeS1heGlzIHRvIHJ1biB1cCB0byAxLCBhbmQgYWRkIGhvcml6b250YWwgbGluZSB0byBlbXBoYXNpemUgdGhlIGJvdHRvbSBvZiB0aGUgZ3JhcGg6CgoKYGBge3J9CmJ1Y2tleWUgJT4lCiAgZ3JvdXBfYnkoR3JhbTIpICU+JQogIHN1bW1hcmlzZSh0ZCA9IG1lYW4odGQpKSAlPiUKICBmaWx0ZXIoR3JhbTIgJWluJSBjKCJwYXN0IiwgInNlbWl3ZWFrIiwgIm1vbm8iKSklPiUKICBnZ3Bsb3QoYWVzKEdyYW0yLCB0ZCkpKwogICAgZ2VvbV9jb2woYWVzKGZpbGw9R3JhbTIpLCBjb2xvciA9ICJibGFjayIpKwogICAgeGxpbSgicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikrCiAgICBzY2FsZV9maWxsX2ZldyhuYW1lID0gIkdyYW1tYXRpY2FsIENsYXNzIiwKICAgICAgICAgICAgICAgICAgIGxpbWl0ID0gYygicGFzdCIsICJzZW1pd2VhayIsICJtb25vIikpKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgeWxpbSgwLDEpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkKYGBgCgo=